home *** CD-ROM | disk | FTP | other *** search
Wrap
/* * $Id: draw.c,v 1.4 2001/02/01 14:36:49 tfrieden Exp $ * * $Date: 2001/02/01 14:36:49 $ * $Revision: 1.4 $ * * (C) 1999 by Hyperion * All rights reserved * * This file is part of the MiniGL library project * See the file Licence.txt for more details * */ // Surgeon: Polygon clip/reject tests: // Primary bottleneck on 68060 is CPU/FPU. // On PPC it is more often bandwidth/fillrate. // The following define adjusts level of rejection-tests #define PRIORITIZE_BANDWIDTH 1 #ifdef __PPC__ #define PRIORITIZE_FILLRATE 1 #endif #include "sysinc.h" #include "vertexarray.h" #include <math.h> #include <stdlib.h> #ifdef __VBCC__ #include <stdio.h> #endif #ifdef DISABLE_TRANSFORMATION #warning "Compiling without transformation pipeline. Only flat geometry supported" #endif static char rcsid[] = "$Id: draw.c,v 1.4 2001/02/01 14:36:49 tfrieden Exp $"; #define DUMP_VERTEX2(vert) //for multitexturing: extern void TMA_Start(LockTimeHandle *handle); extern GLboolean TMA_Check(LockTimeHandle *handle); extern void fog_Set(GLcontext context); void d_DrawPoly(GLcontext context, MGLPolygon *poly); void dh_DrawPolyFF(GLcontext context, MGLPolygon *poly); void d_DrawPoints (GLcontext); void d_DrawLines (GLcontext); void d_DrawLineStrip (GLcontext); void d_DrawTriangles (GLcontext); void d_DrawTriangleFan (GLcontext); void d_DrawTriangleStrip (GLcontext); void d_DrawQuads (GLcontext); void d_DrawFixPoly (GLcontext); void d_DrawMtexPoly (GLcontext); void d_DrawSmoothPoly (GLcontext); void d_DrawNormalPoly (GLcontext); void d_DrawQuadStrip (GLcontext); void d_DrawTrianglesVA (GLcontext); //Surgeon void d_DrawFlat (GLcontext); #if 0 void d_DrawFlatFan (GLcontext); void d_DrawFlatStrip (GLcontext); #endif INLINE GLvoid v_Transform(GLcontext context); #ifndef __VBCC__ //replaced with macro INLINE void v_ToScreen(GLcontext context, int i); #endif extern void m_CombineMatrices(GLcontext context); extern void m_BuildInverted(GLcontext context); extern void hc_ClipAndDrawLine(GLcontext context, MGLPolygon *poly, ULONG or_codes); extern void hc_ClipAndDrawPoly(GLcontext context, MGLPolygon *poly, ULONG or_codes); extern void hc_ClipPoly(GLcontext context, MGLPolygon *poly, PolyBuffer *out, int clipstart, ULONG or_codes); extern void hc_ClipPolyFF(GLcontext context, MGLPolygon *poly, ULONG or_codes); //this index is generated by clip function: static PolyBuffer clip[MGL_MAXVERTS]; //Surgeon: moved from GLVertex*f to after culling: INLINE void PrepTexCoords(GLcontext context, int start, const int numverts, GLboolean cullfan) { int i; GLfloat umul, vmul; MGLVertex *v; if(context->Texture2D_State[0] == GL_TRUE && context->w3dTexBuffer[context->CurrentBinding]) { if (context->w3dChipID == W3D_CHIP_VIRGE) { umul = (float)(context->w3dTexBuffer[context->CurrentBinding]->texwidth-1); vmul = (float)(context->w3dTexBuffer[context->CurrentBinding]->texheight-1); } else { umul = (float)(context->w3dTexBuffer[context->CurrentBinding]->texwidth); vmul = (float)(context->w3dTexBuffer[context->CurrentBinding]->texheight); } if(cullfan == GL_TRUE) { context->VertexBuffer[0].v.u *= umul; context->VertexBuffer[0].v.v *= vmul; } v = &(context->VertexBuffer[start]); i = numverts; do { v->v.u *= umul; v->v.v *= vmul; v++; } while (--i); } } #define CM_0 OF_11 #define CM_1 OF_12 #define CM_2 OF_13 #define CM_3 OF_21 #define CM_4 OF_22 #define CM_5 OF_23 #define CM_6 OF_31 #define CM_7 OF_32 #define CM_8 OF_33 /* ** This computationally intensive piece of code generates coordinates ** for the reflective image used in spherical environment mapping. ** This is a good place for optimizations. ** After generation, transforms into the clipping space... ** ** Note that this is after the book. It is probably a big time-eater. ** ** (Turned out not to be so time intensive after all...) */ void v_GenTexCoords(GLcontext context, int vertex) { #ifdef __M68K__ float u[4]; #endif float ul; float nx,ny,nz; float nu; float rx,ry,rz; float m; float s,t; float a11,a12,a13,a14; float a21,a22,a23,a24; float a31,a32,a33,a34; float a41,a42,a43,a44; float b11,b12,b13,b14; float b21,b22,b23,b24; float b31,b32,b33,b34; float b41,b42,b43,b44; #define a(x) (CurrentMV->v[OF_##x]) #define b(x) (CurrentP->v[OF_##x]) #define verx (context->VertexBuffer[vertex].bx) #define very (context->VertexBuffer[vertex].by) #define verz (context->VertexBuffer[vertex].bz) #define verw (context->VertexBuffer[vertex].bw) #ifdef __PPC__ a11 = a(11); b11 = b(11); a12 = a(12); b12 = b(12); a13 = a(13); b13 = b(13); a14 = a(14); b14 = b(14); a21 = a(21); b21 = b(21); a22 = a(22); b22 = b(22); a23 = a(23); b23 = b(23); a24 = a(24); b24 = b(24); a31 = a(31); b31 = b(31); a32 = a(32); b32 = b(32); a33 = a(33); b33 = b(33); a34 = a(34); b34 = b(34); a41 = a(41); b41 = b(41); a42 = a(42); b42 = b(42); a43 = a(43); b43 = b(43); a44 = a(44); b44 = b(44); #define A_0 a14 #define A_1 a24 #define A_2 a34 #define A_3 a44 #define u(x) (A_##x) #else a11 = a(11); b11 = b(11); a12 = a(12); b12 = b(12); a13 = a(13); b13 = b(13); u[0] = a(14); b14 = b(14); a21 = a(21); b21 = b(21); a22 = a(22); b22 = b(22); a23 = a(23); b23 = b(23); u[1] = a(24); b24 = b(24); a31 = a(31); b31 = b(31); a32 = a(32); b32 = b(32); a33 = a(33); b33 = b(33); u[2] = a(34); b34 = b(34); a41 = a(41); b41 = b(41); a42 = a(42); b42 = b(42); a43 = a(43); b43 = b(43); u[3] = a(44); b44 = b(44); #define u(x) (u[x]) #endif //some common special-case optimizations by surgeon if(context->WOne_Hint == GL_FALSE) { if(!(CurrentMV->flags & MGLMASK_0001)) { u(0) *= verw; u(1) *= verw; u(2) *= verw; u(3) *= verw; u(0) += verz*a13; u(1) += verz*a23; u(2) += verz*a33; u(3) += verz*a43; u(0) += very*a12; u(1) += very*a22; u(2) += very*a32; u(3) += very*a42; u(0) += verx*a11; u(1) += verx*a21; u(2) += verx*a31; u(3) += verx*a41; } else //special case { u(0) *= verw; u(1) *= verw; u(2) *= verw; u(3) = verw; u(0) += verz*a13; u(1) += verz*a23; u(2) += verz*a33; u(0) += very*a12; u(1) += very*a22; u(2) += very*a32; u(0) += verx*a11; u(1) += verx*a21; u(2) += verx*a31; } } else //special case { if(!(CurrentMV->flags & MGLMASK_0001)) { u(0) += verz*a13; u(1) += verz*a23; u(2) += verz*a33; u(3) += verz*a43; u(0) += very*a12; u(1) += very*a22; u(2) += very*a32; u(3) += very*a42; u(0) += verx*a11; u(1) += verx*a21; u(2) += verx*a31; u(3) += verx*a41; } else //special case { u(0) += verz*a13; u(1) += verz*a23; u(2) += verz*a33; u(0) += very*a12; u(1) += very*a22; u(2) += very*a32; u(0) += verx*a11; u(1) += verx*a21; u(2) += verx*a31; } } b14 *= u(3); b24 *= u(3); b34 *= u(3); b44 *= u(3); b14 += u(2)*b13; b24 += u(2)*b23; b34 += u(2)*b33; b44 += u(2)*b43; b14 += u(1)*b12; b24 += u(1)*b22; b34 += u(1)*b32; b44 += u(1)*b42; b14 += u(0)*b11; b24 += u(0)*b21; b34 += u(0)*b31; b44 += u(0)*b41; verx = b14; very = b24; verz = b34; verw = b44; #undef a #undef b #undef verx #undef very #undef verz #undef verw if(u(3) != 1.f) { u(3) = 1.0 / u(3); u(0) *= u(3); u(1) *= u(3); u(2) *= u(3); } ul = (float)sqrt((double)(u(0)*u(0)+u(1)*u(1)+u(2)*u(2))); if (ul == 0.f) return; ul = 1.0 / ul; u(0) *= ul; u(1) *= ul; u(2) *= ul; if(context->NormalBufferPointer > 0) { int nbp = context->VertexBuffer[vertex].normal; #define ver(c) (context->NormalBuffer[nbp].c) #define b(x) (context->InvRot[x]) // InvRot is row-major nx = ver(x)*b(0); ny = ver(x)*b(1); nz = ver(x)*b(2); nx += ver(y)*b(3); ny += ver(y)*b(4); nz += ver(y)*b(5); nx += ver(z)*b(6); ny += ver(z)*b(7); nz += ver(z)*b(8); #undef b #undef ver } else { #define ver(c) (context->NormalBuffer[0].c) #define b(x) (context->InvRot[x]) // InvRot is row-major nx = ver(x)*b(0); ny = ver(x)*b(1); nz = ver(x)*b(2); nx += ver(y)*b(3); ny += ver(y)*b(4); nz += ver(y)*b(5); nx += ver(z)*b(6); ny += ver(z)*b(7); nz += ver(z)*b(8); #undef b #undef ver } nu = nx*u(0) + ny*u(1) + nz*u(2); nu *= 2.f; rx = u(0) - nx*nu; ry = u(1) - ny*nu; rz = u(2) - nz*nu; rz += 1.f; m = 0.5f / (float)sqrt((double)(rx*rx + ry*ry + rz*rz)); if (context->TextureGenS_State == GL_TRUE) { s = rx*m + 0.5; context->VertexBuffer[vertex].v.u = s; } if (context->TextureGenT_State == GL_TRUE) { t = ry*m + 0.5; context->VertexBuffer[vertex].v.v = t; } #undef u } INLINE GLvoid v_Transform(GLcontext context) { #if !defined(DISABLE_TRANSFORMATION) int i; if (context->TextureGenS_State == GL_TRUE || context->TextureGenT_State == GL_TRUE) { #ifndef INLINE_MATRIX_INVERSION if (context->InvRotValid == GL_FALSE) m_BuildInverted(context); #endif for (i=0; i<context->VertexBufferPointer; i++) { v_GenTexCoords(context, i); } } else { if (context->CombinedValid == GL_FALSE) { m_CombineMatrices(context); } if (context->WOne_Hint == GL_FALSE) { #define a(x) (context->CombinedMatrix.v[OF_##x]) float a11 = a(11); float a12 = a(12); float a13 = a(13); float a14 = a(14); float a21 = a(21); float a22 = a(22); float a23 = a(23); float a24 = a(24); float a31 = a(31); float a32 = a(32); float a33 = a(33); float a34 = a(34); float a41 = a(41); float a42 = a(42); float a43 = a(43); float a44 = a(44); MGLVertex *v = &context->VertexBuffer[0]; i = context->VertexBufferPointer; do { float x = v->bx; float y = v->by; float z = v->bz; float w = v->bw; v->bx = a11*x + a12*y + a13*z + a14*w; v->by = a21*x + a22*y + a23*z + a24*w; v->bz = a31*x + a32*y + a33*z + a34*w; v->bw = a41*x + a42*y + a43*z + a44*w; v++; } while (--i); #undef a } else { #define a(x) (context->CombinedMatrix.v[OF_##x]) float a11 = a(11); float a12 = a(12); float a13 = a(13); float a14 = a(14); float a21 = a(21); float a22 = a(22); float a23 = a(23); float a24 = a(24); float a31 = a(31); float a32 = a(32); float a33 = a(33); float a34 = a(34); float a41 = a(41); float a42 = a(42); float a43 = a(43); float a44 = a(44); MGLVertex *v = &context->VertexBuffer[0]; i = context->VertexBufferPointer; do { float x = v->bx; float y = v->by; float z = v->bz; v->bx = a11*x + a12*y + a13*z + a14; v->by = a21*x + a22*y + a23*z + a24; v->bz = a31*x + a32*y + a33*z + a34; v->bw = a41*x + a42*y + a43*z + a44; v++; } while (--i); #undef a } } #else // Does nothing #endif } #ifdef __VBCC__ //VBCC only does inlining on highest optimization level :-/ #define v_ToScreen(ctx,vnum){\ static float wdiv;\ wdiv = 1.0 / ctx->VertexBuffer[vnum].bw; \ ctx->VertexBuffer[vnum].v.x = ctx->ax + ctx->VertexBuffer[vnum].bx * wdiv * ctx->sx; \ ctx->VertexBuffer[vnum].v.y = ctx->ay - ctx->VertexBuffer[vnum].by * wdiv * ctx->sy; \ ctx->VertexBuffer[vnum].v.z = ctx->az + ctx->VertexBuffer[vnum].bz * wdiv * ctx->sz; \ if (ctx->ZOffset_State == GL_TRUE) ctx->VertexBuffer[vnum].v.z += (W3D_Float)ctx->ZOffset; \ if (context->CurrentTexQValid == GL_FALSE) ctx->VertexBuffer[vnum].v.w = wdiv; \ else ctx->VertexBuffer[vnum].v.w = ctx->VertexBuffer[vnum].q;}\ #define v_ToScreenVA(ctx,vnum){\ static float wdiv;\ wdiv = 1.0 / ctx->VertexBuffer[vnum].bw; \ ctx->VertexBuffer[vnum].bx = ctx->ax + ctx->VertexBuffer[vnum].bx * wdiv * ctx->sx; \ ctx->VertexBuffer[vnum].by = ctx->ay - ctx->VertexBuffer[vnum].by * wdiv * ctx->sy; \ ctx->VertexBuffer[vnum].bz = ctx->az + ctx->VertexBuffer[vnum].bz * wdiv * ctx->sz; \ if (ctx->ZOffset_State == GL_TRUE) ctx->VertexBuffer[vnum].bz += (W3D_Float)ctx->ZOffset; \ if (context->CurrentTexQValid == GL_FALSE) ctx->VertexBuffer[vnum].v.w = wdiv; \ else ctx->VertexBuffer[vnum].v.w = ctx->VertexBuffer[vnum].q;}\ #else INLINE void v_ToScreen(GLcontext context, int i) { #if !defined(DISABLE_TRANSFORMATION) float w; w = 1.0 / context->VertexBuffer[i].bw; context->VertexBuffer[i].v.x = context->ax + context->VertexBuffer[i].bx * w * context->sx; context->VertexBuffer[i].v.y = context->ay - context->VertexBuffer[i].by * w * context->sy; context->VertexBuffer[i].v.z = context->az + context->VertexBuffer[i].bz * w * context->sz; if (context->ZOffset_State == GL_TRUE) context->VertexBuffer[i].v.z += (W3D_Float)context->ZOffset; if (context->CurrentTexQValid == GL_FALSE) context->VertexBuffer[i].v.w = w; else context->VertexBuffer[i].v.w = context->VertexBuffer[i].q; #else context->VertexBuffer[i].v.x = context->VertexBuffer[i].bx; context->VertexBuffer[i].v.y = context->VertexBuffer[i].by; context->VertexBuffer[i].v.z = 1.0 - context->VertexBuffer[i].bz; context->VertexBuffer[i].v.w = context->VertexBuffer[i].q; #endif } INLINE void v_ToScreenVA(GLcontext context, int i) { float w; w = 1.0 / context->VertexBuffer[i].bw; context->VertexBuffer[i].bx = context->ax + context->VertexBuffer[i].bx * w * context->sx; context->VertexBuffer[i].by = context->ay - context->VertexBuffer[i].by * w * context->sy; context->VertexBuffer[i].bz = context->az + context->VertexBuffer[i].bz * w * context->sz; if (context->ZOffset_State == GL_TRUE) context->VertexBuffer[i].bz += (W3D_Float)context->ZOffset; if (context->CurrentTexQValid == GL_FALSE) context->VertexBuffer[i].v.w = w; else context->VertexBuffer[i].v.w = context->VertexBuffer[i].q; } #endif /* ** Multitexturing: ** See mglDrawMultitexBuffer */ #define ENABLE_BLEND {if(mini_CurrentContext->Blend_State == GL_FALSE) W3D_SetState(context->w3dContext, W3D_BLENDING, W3D_ENABLE);} #define DISABLE_BLEND {if(mini_CurrentContext->Blend_State == GL_FALSE) W3D_SetState(context->w3dContext, W3D_BLENDING, W3D_DISABLE);} #if 0 //should go to same buffer as GL_POLYGON static void Multitex_PolyBuffer(GLcontext context, W3D_Vertex **verts, int numpolys, GLboolean typecheck) { int i,j; int first; ULONG error; static W3D_TrianglesV tris; ENABLE_BLEND tris.tex = context->w3dTexBuffer[context->VirtualBinding]; tris.st_pattern = NULL; i = 0; first = 0; do { PolyBuffer *p = &clip[i]; float w = context->w3dTexBuffer[context->VirtualBinding]->texwidth; float h = context->w3dTexBuffer[context->VirtualBinding]->texheight; for(j=0; j<p->numverts; j++) { MGLVertex *v = &context->VertexBuffer[p->verts[j]]; v->v.u = v->tcoord.s * w; v->v.v = v->tcoord.t * h; } tris.v = &verts[first]; tris.vertexcount = p->numverts; first += p->numverts; if(typecheck && p->type == W3D_PRIMITIVE_TRISTRIP) { error = W3D_DrawTriStripV(context->w3dContext, &tris); } else { error = W3D_DrawTriFanV(context->w3dContext, &tris); } i++; } while (i<numpolys); DISABLE_BLEND } #endif //Surgeon: from hclip.c - hc_CodePoint is inlined manually #define CLIP_EPS (1e-7) //primitive point emulation by Surgeon - works on voodoo3 void d_DrawPoints(GLcontext context) { #if !defined(DISABLE_TRANSFORMATION) int i,j; W3D_Triangle tri; MGLVertex *vf; ULONG error; if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK) return; v_Transform(context); vf = context->VertexBuffer; for (i=0; i<context->VertexBufferPointer; i++) { MGLVertex *v = &vf[i]; float w = v->bw; if (w < CLIP_EPS ) { continue; } if (-w > v->bx) { continue; } else if (v->bx > w) { continue; } if (-w > v->by) { continue; } else if (v->by > w) { continue; } if (-w > v->bz) { continue; } else if (v->bz > w) { continue; } v_ToScreen(context, i); tri.v1 = context->VertexBuffer[i].v; tri.v2 = context->VertexBuffer[i].v; tri.v3 = context->VertexBuffer[i].v; tri.v2.y += context->CurrentPointSize; tri.v3.x += context->CurrentPointSize; tri.tex = NULL; tri.st_pattern = NULL; error = W3D_DrawTriangle(context->w3dContext, &tri); } #else int i; W3D_Point p; ULONG error; for (i=0;i<context->VertexBufferPointer; i++) { v_ToScreen(context,i); p.v1 = (context->VertexBuffer[i].v); p.tex = NULL; p.pointsize = 1; //diameter error = W3D_DrawPoint(context->w3dContext, &p); } #endif } void d_DrawLines(GLcontext context) { #if !defined(DISABLE_TRANSFORMATION) int i,j; W3D_Line lin; ULONG or_code, and_code; ULONG error; if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK) return; v_Transform(context); for (i=0; i<context->VertexBufferPointer; i+=2) { for (j=i; j<i+2;j++) { MGLVertex *v = &(context->VertexBuffer[j]); float w = v->bw; ULONG outcode = 0; if (w < CLIP_EPS ) { outcode |= MGL_CLIP_NEGW; } if (-w > v->bx) { outcode |= MGL_CLIP_LEFT; } else if (v->bx > w) { outcode |= MGL_CLIP_RIGHT; } if (-w > v->by) { outcode |= MGL_CLIP_BOTTOM; } else if (v->by > w) { outcode |= MGL_CLIP_TOP; } if (-w > v->bz) { outcode |= MGL_CLIP_BACK; } else if (v->bz > w) { outcode |= MGL_CLIP_FRONT; } v->outcode = outcode; and_code &= outcode; or_code |= outcode; } or_code = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode; and_code = context->VertexBuffer[i+0].outcode & context->VertexBuffer[i+1].outcode; if (and_code) continue; PrepTexCoords(context, i, 2, GL_FALSE); if (or_code == 0) { v_ToScreen(context, i); v_ToScreen(context, i+1); lin.v1 = (context->VertexBuffer[i+0].v); lin.v2 = (context->VertexBuffer[i+1].v); lin.tex = context->w3dTexBuffer[context->CurrentBinding]; lin.st_pattern = 0; lin.st_enable = 0; lin.st_factor = 1; error = W3D_DrawLine(context->w3dContext, &lin); // if (error != W3D_SUCCESS) kprintf("W3D_DrawTriangle = %ld\n",error); } else { static MGLPolygon poly; poly.numverts = 2; poly.verts[0] = i; poly.verts[1] = i+1; hc_ClipAndDrawLine(context, &poly, or_code); } } #else int i; W3D_Line lin; ULONG error; PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE); for (i=0;i<context->VertexBufferPointer; i+=2) { v_ToScreen(context,i); v_ToScreen(context,i+1); lin.v1 = (context->VertexBuffer[i+0].v); lin.v2 = (context->VertexBuffer[i+1].v); lin.tex = context->w3dTexBuffer[context->CurrentBinding]; lin.st_pattern = 0; lin.st_enable = 0; lin.st_factor = 1; error = W3D_DrawLine(context->w3dContext, &lin); // if (error != W3D_SUCCESS) kprintf("W3D_DrawTriangle = %ld\n", error); } #endif } void dh_DrawLine(GLcontext context, MGLPolygon *poly) { ULONG error; static W3D_Line lin; v_ToScreen(context, poly->verts[0]); lin.v1 = (context->VertexBuffer[poly->verts[0]].v); v_ToScreen(context, poly->verts[1]); lin.v2 = (context->VertexBuffer[poly->verts[1]].v); lin.tex = context->w3dTexBuffer[context->CurrentBinding]; lin.st_pattern = 0; lin.st_enable = 0; lin.st_factor = 1; #ifndef NODRAW error = W3D_DrawLine(context->w3dContext, &lin); // if (error != W3D_SUCCESS) kprintf("W3D_DrawTriFan = %ld\n", error); #endif } void d_DrawLineStrip(GLcontext context) { } //surgeon: added fast path when primitive or_code equals 0 //surgeon: added buffering for clipping events //multitexturing not finished yet void d_DrawTriangleFan(GLcontext context) { #if !defined(DISABLE_TRANSFORMATION) int i,j; ULONG and_code, or_code; ULONG local_or, local_and, guard_band; ULONG error; static W3D_Vertex **verts = NULL; static GLboolean visible[MGL_MAXVERTS]; // Should be enough...? static ULONG complete[MGL_MAXVERTS]; // Ditto static W3D_TrianglesV fan; int triangle; int pnum, free, backface, first, size; if (verts == NULL) { verts = (W3D_Vertex **)malloc(sizeof(W3D_Vertex *) * context->VertexBufferSize); if (!verts) return; } if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK) return; v_Transform(context); and_code = 0xff; or_code = 0; for (i=0; i<context->VertexBufferPointer; i++) { MGLVertex *v = &(context->VertexBuffer[i]); float w = v->bw; ULONG outcode = 0; if (w < CLIP_EPS ) { outcode |= MGL_CLIP_NEGW; } if (-w > v->bx) { outcode |= MGL_CLIP_LEFT; } else if (v->bx > w) { outcode |= MGL_CLIP_RIGHT; } if (-w > v->by) { outcode |= MGL_CLIP_BOTTOM; } else if (v->by > w) { outcode |= MGL_CLIP_TOP; } if (-w > v->bz) { outcode |= MGL_CLIP_BACK; } else if (v->bz > w) { outcode |= MGL_CLIP_FRONT; } v->outcode = outcode; and_code &= outcode; or_code |= outcode; } if (and_code) { return; } else if(or_code == 0 || (or_code & context->ClipFlags)) { guard_band = or_code; } else { float gcw; ULONG guard_code; MGLVertex *v = &context->VertexBuffer[0]; i = context->VertexBufferPointer; guard_band = 0; do { if(v->outcode) { gcw = v->bw * 2.0; guard_code = 0; if (-gcw > v->bx) guard_code |= MGL_CLIP_LEFT; else if (v->bx > gcw) guard_code |= MGL_CLIP_RIGHT; if (-gcw > v->by) guard_code |= MGL_CLIP_BOTTOM; else if (v->by > gcw) guard_code |= MGL_CLIP_TOP; guard_band |= guard_code; } v++; } while (--i && guard_band == 0); } if (guard_band == 0) //trifan completely visible { first = 0; size = context->VertexBufferPointer; v_ToScreen(context, 0); v_ToScreen(context, 1); v_ToScreen(context, 2); i = 3; while (i < context->VertexBufferPointer) { v_ToScreen(context, i); i++; } if(context->CullFace_State == GL_TRUE) { float area; float sign; float x0,y0; float x1,y1; float x2,y2; sign = (float)(-context->CurrentCullSign); #define x(i) (context->VertexBuffer[i].v.x) #define y(i) (context->VertexBuffer[i].v.y) backface = 0; if(size == 3) { x1 = x(1) - x(0); y1 = y(1) - y(0); x2 = x(2) - x(0); y2 = y(2) - y(0); area = y2*x1 - x2*y1; area *= sign; } else { x0 = x(0); y0 = y(0); x1 = x(1) - x0; y1 = y(1) - y0; x2 = x(2) - x0; y2 = y(2) - y0; area = y2*x1 - x2*y1; area *= sign; if(area < 0.f) { first++; area = 0.f; } i = 1; do { float area2; x1 = x2; y1 = y2; x2 = x(i+2) - x0; y2 = y(i+2) - y0; area2 = y2*x1 - x2*y1; area2 *= sign; if(area2 < 0.f) { if(first == i) first++; else backface++; } else { backface = 0; area += area2; } i++; } while (i < size-2); size -= backface+first; } if (area < context->MinTriArea) return; } #undef x #undef y verts[0] = &(context->VertexBuffer[0].v); i = 1; do { verts[i] = &(context->VertexBuffer[i+first].v); i++; } while (i < size); PrepTexCoords(context, first+1, size-1, GL_TRUE); fan.tex = context->w3dTexBuffer[context->CurrentBinding]; fan.vertexcount = size; fan.st_pattern = NULL; fan.v = &verts[0]; W3D_DrawTriFanV(context->w3dContext, &fan); return; } /* ** Up to now everything is like a polygon. Unlike a polygon, however, ** triangle fans and strips may be concave, and each individual triangle ** might be backfacing. ** ** We calculate how many of the triangles are visible. */ backface = 0; if(context->CullFace_State == GL_FALSE) { for (i=1,triangle=0; i<context->VertexBufferPointer - 1; i++, triangle++) { local_or = context->VertexBuffer[0].outcode | context->VertexBuffer[i].outcode | context->VertexBuffer[i+1].outcode; local_and = context->VertexBuffer[0].outcode & context->VertexBuffer[i].outcode & context->VertexBuffer[i+1].outcode; if (local_and == 0) // if the local and code is zero, we're not { // completely off screen. // if our local or codes are zero, we are completely visible complete[triangle] = local_or; visible[triangle] = GL_TRUE; backface = 0; } else { visible[triangle] = GL_FALSE; backface++; } } } else { for (i=1,triangle=0; i<context->VertexBufferPointer - 1; i++, triangle++) { local_or = context->VertexBuffer[0].outcode | context->VertexBuffer[i].outcode | context->VertexBuffer[i+1].outcode; local_and = context->VertexBuffer[0].outcode & context->VertexBuffer[i].outcode & context->VertexBuffer[i+1].outcode; if (local_and == 0) // if the local and code is zero, we're not { // completely off screen. // if our local or codes are zero, we are completely visible complete[triangle] = local_or; if (local_or & MGL_CLIP_NEGW) { visible[triangle] = GL_TRUE; backface = 0; } else { visible[triangle] = hc_DecideFrontface(context, &(context->VertexBuffer[0]), &(context->VertexBuffer[i]), &(context->VertexBuffer[i+1])); if(visible[triangle] == GL_FALSE) backface++; else backface = 0; } } else { visible[triangle] = GL_FALSE; backface++; } } } //early out: if(triangle == backface) return; context->VertexBufferPointer -= backface; //surgeon 260302 PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE); /* ** Draw... ** There are three cases: ** ** 1) Triangle is partially visible ** 2) Triangle is fully visible ** 3) Triangle is invisible ** ** In case 1, we draw the triangle with clip_ClipAndDrawPoly. ** In case 2, we collect a triangle fan/strip of maximum length ** and draw that directly ** in case 3... WE IGNORE IT! HA! */ free = context->VertexBufferPointer; pnum = 0; triangle = 0; i=1; do { if (visible[triangle] == GL_FALSE) // case 3 { triangle ++; i ++; } else { if (complete[triangle]) // case 1 { static MGLPolygon poly; poly.numverts = 3; poly.verts[0] = 0; poly.verts[1] = i; poly.verts[2] = i + 1; hc_ClipPoly(context, &poly, &clip[pnum], free, complete[triangle]); triangle++; i++; if(clip[pnum].numverts) { free = clip[pnum].nextfree; pnum++; } } else { // case 2 (the difficult part) int k=3; clip[pnum].verts[0] = 0; clip[pnum].verts[1] = i; clip[pnum].verts[2] = i+1; triangle ++; i ++; while (complete[triangle]==0 && visible[triangle] && i<context->VertexBufferPointer - 1) { clip[pnum].verts[k] = i+1; i++; k++; triangle++; } clip[pnum].numverts = k; pnum++; } } } while (i<context->VertexBufferPointer-1); //Project to screen and draw: visible[context->VertexBufferPointer-2] = GL_FALSE; visible[context->VertexBufferPointer-1] = GL_FALSE; //project clipverts for(i=context->VertexBufferPointer; i<free; i++) { v_ToScreen(context, i); } fan.tex = context->w3dTexBuffer[context->CurrentBinding]; fan.st_pattern = NULL; j = 0, first = 0; do { PolyBuffer *p = &clip[j]; for (i=0; i<p->numverts; i++) { int vert = p->verts[i]; if(vert < context->VertexBufferPointer && visible[vert] < 2 /*== GL_FALSE*/) { visible[vert] = 2/*GL_TRUE*/; v_ToScreen(context, vert); } verts[i+first] = &(context->VertexBuffer[vert].v); } fan.vertexcount = p->numverts; fan.v = &verts[first]; first += p->numverts; error = W3D_DrawTriFanV(context->w3dContext, &fan); j++; } while (j < pnum); #if 0 if(context->Texture2D_State[1]) Multitex_PolyBuffer(context, verts, pnum, GL_FALSE); #endif #else int i; ULONG error; static W3D_Vertex *verts[MGL_MAXVERTS]; static W3D_TrianglesV tris; PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE); for (i=0; i<context->VertexBufferPointer; i++) { v_ToScreen(context, i); verts[i] = &(context->VertexBuffer[i].v); } tris.tex = context->w3dTexBuffer[context->CurrentBinding]; tris.st_pattern = NULL; tris.vertexcount = context->VertexBufferPointer; tris.v = verts; #ifndef NODRAW error = W3D_DrawTriFanV(context->w3dContext, &tris); #endif #endif } //surgeon: added fast path when primitive or_code equals 0 //surgeon: added buffering for clipping events //multitexturing not finished yet void d_DrawTriangleStrip(GLcontext context) { #if !defined(DISABLE_TRANSFORMATION) int i,j; ULONG and_code, or_code, guard_band; ULONG local_or, local_and; ULONG error; static W3D_Vertex **verts = NULL; static GLboolean visible[MGL_MAXVERTS]; // Should be enough...? static ULONG complete[MGL_MAXVERTS]; // Ditto static W3D_TrianglesV tris; int triangle = 0; /* GLenum CurrentFrontFace = context->CurrentFrontFace; */ GLint CurrentCullSign = context->CurrentCullSign; int pnum, free, backface, first, size; if (verts == NULL) { verts = (W3D_Vertex **)malloc(sizeof(W3D_Vertex *) * context->VertexBufferSize); if (!verts) return; } if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK) return; v_Transform(context); and_code = 0xff; or_code = 0; for (i=0; i<context->VertexBufferPointer; i++) { MGLVertex *v = &(context->VertexBuffer[i]); float w = v->bw; ULONG outcode = 0; if (w < CLIP_EPS ) { outcode |= MGL_CLIP_NEGW; } if (-w > v->bx) { outcode |= MGL_CLIP_LEFT; } else if (v->bx > w) { outcode |= MGL_CLIP_RIGHT; } if (-w > v->by) { outcode |= MGL_CLIP_BOTTOM; } else if (v->by > w) { outcode |= MGL_CLIP_TOP; } if (-w > v->bz) { outcode |= MGL_CLIP_BACK; } else if (v->bz > w) { outcode |= MGL_CLIP_FRONT; } v->outcode = outcode; and_code &= outcode; or_code |= outcode; } if (and_code) return; else if(or_code == 0 || (or_code & context->ClipFlags)) { guard_band = or_code; } else { float gcw; ULONG guard_code; MGLVertex *v = &context->VertexBuffer[0]; i = context->VertexBufferPointer; guard_band = 0; do { if(v->outcode) { gcw = v->bw * 2.0; guard_code = 0; if (-gcw > v->bx) guard_code |= MGL_CLIP_LEFT; else if (v->bx > gcw) guard_code |= MGL_CLIP_RIGHT; if (-gcw > v->by) guard_code |= MGL_CLIP_BOTTOM; else if (v->by > gcw) guard_code |= MGL_CLIP_TOP; guard_band |= guard_code; } v++; } while (--i && guard_band == 0); } if (guard_band == 0) //tristrip completely visible { first = 0; size = context->VertexBufferPointer; v_ToScreen(context, 0); v_ToScreen(context, 1); v_ToScreen(context, 2); i = 3; while (i < context->VertexBufferPointer) { v_ToScreen(context, i); i++; } if(context->CullFace_State == GL_TRUE) { float x1,y1; float x2,y2; float area; float sign; sign = (float)(-context->CurrentCullSign); #define x(i) (context->VertexBuffer[i].v.x) #define y(i) (context->VertexBuffer[i].v.y) backface = 0; if(size == 3) { x1 = x(1) - x(0); y1 = y(1) - y(0); x2 = x(2) - x(0); y2 = y(2) - y(0); area = y2*x1 - x2*y1; area *= sign; } else { float a1 = x(1); float b1 = y(1); float a2 = x(2); float b2 = y(2); x1 = a1 - x(0); y1 = b1 - y(0); x2 = a2 - x(0); y2 = b2 - y(0); area = y2*x1 - x2*y1; area *= sign; if(area < 0.f) { first++; area = 0.f; } i = 1; do { float area2; sign = -sign; //reverse order x1 = a2 - a1; y1 = b2 - b1; x2 = x(i+2) - a1; y2 = y(i+2) - b1; a1 = a2; b1 = b2; a2 = x(i+2); b2 = y(i+2); area2 = y2*x1 - x2*y1; area2 *= sign; if(area2 < 0.f) { if(first == i) first++; else backface++; } else { backface = 0; area += area2; } i++; } while (i < size-2); size -= backface+first; } if (area < context->MinTriArea) return; } #undef x #undef y i = 0; do { verts[i] = &(context->VertexBuffer[first+i].v); i++; } while (i < size); PrepTexCoords(context, first, size, GL_FALSE); tris.tex = context->w3dTexBuffer[context->CurrentBinding]; tris.vertexcount = size; tris.v = &verts[0]; tris.st_pattern = NULL; W3D_DrawTriStripV(context->w3dContext, &tris); return; } /* ** Up to now everything is like a polygon. Unlike a polygon, however, ** triangle fans and strips may be concave, and each individual triangle ** might be backfacing. ** ** We calculate how many of the triangles are visible. */ backface = 0; if(context->CullFace_State == GL_FALSE) { for (triangle=0; triangle<context->VertexBufferPointer - 2; triangle++) { local_or = context->VertexBuffer[triangle+0].outcode | context->VertexBuffer[triangle+1].outcode | context->VertexBuffer[triangle+2].outcode; local_and = context->VertexBuffer[triangle+0].outcode & context->VertexBuffer[triangle+1].outcode & context->VertexBuffer[triangle+2].outcode; // if the local and code is zero, we're not completely off screen. if (local_and == 0) { complete[triangle] = local_or; visible[triangle] = GL_TRUE; backface = 0; } else { visible[triangle] = GL_FALSE; backface++; } } } else { for (triangle=0; triangle<context->VertexBufferPointer - 2; triangle++) { local_or = context->VertexBuffer[triangle].outcode | context->VertexBuffer[triangle+1].outcode | context->VertexBuffer[triangle+2].outcode; local_and = context->VertexBuffer[triangle].outcode & context->VertexBuffer[triangle+1].outcode & context->VertexBuffer[triangle+2].outcode; // if the local and code is zero, we're not completely off screen. if (local_and == 0) { complete[triangle] = local_or; if(local_or & MGL_CLIP_NEGW) { visible[triangle] = GL_TRUE; backface = 0; } else { visible[triangle] = hc_DecideFrontface(context, &(context->VertexBuffer[triangle]), &(context->VertexBuffer[triangle+1]), &(context->VertexBuffer[triangle+2])); if(visible[triangle] == GL_FALSE) backface++; else backface = 0; } } else { visible[triangle] = GL_FALSE; backface++; } context->CurrentCullSign = -context->CurrentCullSign; } } context->CurrentCullSign = CurrentCullSign; //early out: if(triangle == backface) return; context->VertexBufferPointer -= backface; //surgeon 260302 PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE); /* ** Draw... ** There are three cases: ** ** 1) Triangle is partially visible ** 2) Triangle is fully visible ** 3) Triangle is invisible ** ** In case 1, we draw the triangle with clip_ClipAndDrawPoly. ** In case 2, we collect a triangle fan/strip of maximum length ** and draw that directly ** in case 3... WE IGNORE IT! HA! */ free = context->VertexBufferPointer; pnum = 0; triangle = 0; do { if (visible[triangle] == GL_FALSE) // case 3 { triangle ++; } else { if (complete[triangle]) // case 1 { static MGLPolygon poly; poly.numverts = 3; poly.verts[0] = triangle + 0; poly.verts[1] = triangle + 1; poly.verts[2] = triangle + 2; hc_ClipPoly(context, &poly, &clip[pnum], free, complete[triangle]); if(clip[pnum].numverts) { clip[pnum].type = W3D_PRIMITIVE_TRIFAN; free = clip[pnum].nextfree; pnum++; } triangle++; } else { // case 2 (the difficult part) int k=3; clip[pnum].verts[0] = triangle; clip[pnum].verts[1] = triangle+1; clip[pnum].verts[2] = triangle+2; triangle++; while (complete[triangle]==0 && visible[triangle] && triangle<context->VertexBufferPointer - 2 && k < 64) { clip[pnum].verts[k] = triangle+2; k++; triangle++; } clip[pnum].numverts = k; clip[pnum].type = W3D_PRIMITIVE_TRISTRIP; pnum++; } } } while (triangle<context->VertexBufferPointer - 2); //Project to screen and Draw: visible[context->VertexBufferPointer-2] = GL_FALSE; visible[context->VertexBufferPointer-1] = GL_FALSE; //project clipverts without index lookup for(i=context->VertexBufferPointer; i<free; i++) { v_ToScreen(context, i); } tris.tex = context->w3dTexBuffer[context->CurrentBinding]; tris.st_pattern = NULL; j = 0; first = 0; do { PolyBuffer *p = &clip[j]; for (i=0; i<p->numverts; i++) { int vert = p->verts[i]; if(vert < context->VertexBufferPointer && visible[vert] < 2) { v_ToScreen(context, vert); visible[vert] = 2; } verts[i+first] = &(context->VertexBuffer[vert].v); } tris.vertexcount = p->numverts; tris.v = &verts[first]; if(p->type == W3D_PRIMITIVE_TRIFAN) { error = W3D_DrawTriFanV(context->w3dContext, &tris); } else { error = W3D_DrawTriStripV(context->w3dContext, &tris); } first += p->numverts; j++; } while (j < pnum); #if 0 if(context->Texture2D_State[1]) Multitex_PolyBuffer(context, verts, pnum, GL_TRUE); #endif #else int i; ULONG error; static W3D_Vertex *verts[MGL_MAXVERTS]; static W3D_TrianglesV tris; PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE); for (i=0; i<context->VertexBufferPointer-1; i++) { v_ToScreen(context, i); verts[i] = &(context->VertexBuffer[i].v); } tris.tex = context->w3dTexBuffer[context->CurrentBinding]; tris.st_pattern = NULL; tris.vertexcount = context->VertexBufferPointer-1; tris.v = verts; #ifndef NODRAW error = W3D_DrawTriStripV(context->w3dContext, &tris); #endif #endif } void d_DrawQuadStrip(GLcontext context) { #if !defined(DISABLE_TRANSFORMATION) int i,j; ULONG or_code, and_code; ULONG error; static W3D_Vertex *verts[4]; static W3D_TrianglesV tris; if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK) return; v_Transform(context); PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE); for (j=0; j<context->VertexBufferPointer; j++) { MGLVertex *v = &(context->VertexBuffer[j]); float w = v->bw; ULONG outcode = 0; if (w < CLIP_EPS ) { outcode |= MGL_CLIP_NEGW; } if (-w > v->bx) { outcode |= MGL_CLIP_LEFT; } else if (v->bx > w) { outcode |= MGL_CLIP_RIGHT; } if (-w > v->by) { outcode |= MGL_CLIP_BOTTOM; } else if (v->by > w) { outcode |= MGL_CLIP_TOP; } if (-w > v->bz) { outcode |= MGL_CLIP_BACK; } else if (v->bz > w) { outcode |= MGL_CLIP_FRONT; } v->outcode = outcode; } for (i=0; i<context->VertexBufferPointer-2; i+=2) { or_code = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode | context->VertexBuffer[i+2].outcode | context->VertexBuffer[i+3].outcode; and_code = context->VertexBuffer[i+0].outcode & context->VertexBuffer[i+1].outcode & context->VertexBuffer[i+2].outcode & context->VertexBuffer[i+3].outcode; if (and_code) continue; if(context->CullFace_State == GL_TRUE && !(or_code & MGL_CLIP_NEGW)) { if (hc_DecideFrontface(context, &(context->VertexBuffer[i]), &(context->VertexBuffer[i+1]), &(context->VertexBuffer[i+2])) == GL_FALSE) continue; } if (or_code == 0) { v_ToScreen(context, i); v_ToScreen(context, i+1); v_ToScreen(context, i+2); v_ToScreen(context, i+3); verts[0] = &(context->VertexBuffer[i+0].v); verts[1] = &(context->VertexBuffer[i+1].v); verts[2] = &(context->VertexBuffer[i+3].v); verts[3] = &(context->VertexBuffer[i+2].v); tris.tex = context->w3dTexBuffer[context->CurrentBinding]; tris.st_pattern = NULL; tris.vertexcount = 4; tris.v = verts; error = W3D_DrawTriFanV(context->w3dContext, &tris); } else { static MGLPolygon poly; poly.numverts = 4; poly.verts[0] = i; poly.verts[1] = i+1; poly.verts[2] = i+3; poly.verts[3] = i+2; hc_ClipAndDrawPoly(context, &poly, or_code); } } #else int i; ULONG error; static W3D_Vertex *verts[4]; static W3D_TrianglesV tris; PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE); for (i=0; i<context->VertexBufferPointer-2; i+=2) { v_ToScreen(context, i); v_ToScreen(context, i+1); v_ToScreen(context, i+2); v_ToScreen(context, i+3); verts[0] = &(context->VertexBuffer[i+0].v); verts[1] = &(context->VertexBuffer[i+1].v); verts[2] = &(context->VertexBuffer[i+3].v); verts[3] = &(context->VertexBuffer[i+2].v); tris.tex = context->w3dTexBuffer[context->CurrentBinding]; tris.st_pattern = NULL; tris.vertexcount = 4; tris.v = verts; error = W3D_DrawTriFanV(context->w3dContext, &tris); } #endif } void d_DrawQuads(GLcontext context) { #if !defined(DISABLE_TRANSFORMATION) int i,j; ULONG or_code, and_code; ULONG error; static W3D_Vertex *verts[4]; static W3D_TrianglesV tris; if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK) return; v_Transform(context); for (i=0; i<context->VertexBufferPointer; i+=4) { for (j=i; j<i+4;j++) { MGLVertex *v = &(context->VertexBuffer[j]); float w = v->bw; ULONG outcode = 0; if (w < CLIP_EPS ) { outcode |= MGL_CLIP_NEGW; } if (-w > v->bx) { outcode |= MGL_CLIP_LEFT; } else if (v->bx > w) { outcode |= MGL_CLIP_RIGHT; } if (-w > v->by) { outcode |= MGL_CLIP_BOTTOM; } else if (v->by > w) { outcode |= MGL_CLIP_TOP; } if (-w > v->bz) { outcode |= MGL_CLIP_BACK; } else if (v->bz > w) { outcode |= MGL_CLIP_FRONT; } v->outcode = outcode; } or_code = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode | context->VertexBuffer[i+2].outcode | context->VertexBuffer[i+3].outcode; and_code = context->VertexBuffer[i+0].outcode & context->VertexBuffer[i+1].outcode & context->VertexBuffer[i+2].outcode & context->VertexBuffer[i+3].outcode; if (and_code) continue; if(context->CullFace_State == GL_TRUE && !(or_code & MGL_CLIP_NEGW)) { if (hc_DecideFrontface(context, &(context->VertexBuffer[i]), &(context->VertexBuffer[i+1]), &(context->VertexBuffer[i+2])) == GL_FALSE) continue; } PrepTexCoords(context, i, 4, GL_FALSE); if (or_code == 0) { v_ToScreen(context, i); v_ToScreen(context, i+1); v_ToScreen(context, i+2); v_ToScreen(context, i+3); verts[0] = &(context->VertexBuffer[i+0].v); verts[1] = &(context->VertexBuffer[i+1].v); verts[2] = &(context->VertexBuffer[i+2].v); verts[3] = &(context->VertexBuffer[i+3].v); tris.tex = context->w3dTexBuffer[context->CurrentBinding]; tris.st_pattern = NULL; tris.vertexcount = 4; tris.v = verts; #ifndef NODRAW error = W3D_DrawTriFanV(context->w3dContext, &tris); #else printf("d_DrawQuads\n"); DUMP_VERTEX(context->VertexBuffer[i+0]); DUMP_VERTEX(context->VertexBuffer[i+1]); DUMP_VERTEX(context->VertexBuffer[i+2]); DUMP_VERTEX(context->VertexBuffer[i+3]); printf("-----------------------------------\n"); #endif } else { static MGLPolygon poly; poly.numverts = 4; poly.verts[0] = i; poly.verts[1] = i+1; poly.verts[2] = i+2; poly.verts[3] = i+3; hc_ClipAndDrawPoly(context, &poly, or_code); } } #else int i; ULONG error; static W3D_Vertex *verts[4]; static W3D_TrianglesV tris; PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE); for (i=0; i<context->VertexBufferPointer; i+=4) { v_ToScreen(context, i); v_ToScreen(context, i+1); v_ToScreen(context, i+2); v_ToScreen(context, i+3); verts[0] = &(context->VertexBuffer[i+0].v); verts[1] = &(context->VertexBuffer[i+1].v); verts[2] = &(context->VertexBuffer[i+2].v); verts[3] = &(context->VertexBuffer[i+3].v); tris.tex = context->w3dTexBuffer[context->CurrentBinding]; tris.st_pattern = NULL; tris.vertexcount = 4; tris.v = verts; error = W3D_DrawTriFanV(context->w3dContext, &tris); } #endif } //For chaining and buffering multitexture-polys: typedef struct MtexPolyIdx_s { W3D_Texture *tmu[2]; GLuint first; GLuint count; } MtexPolyIdx; //alternative to W3D_Vertex: typedef struct W3D_VAVertex_s { float x,y,z,w; float s1,t1,s2,t2; ULONG color; ULONG _pad_[3]; //16 byte align } W3D_VAVertex; #define MTEX_INDEXSIZE 1024 #define MTEX_VERTEXBUFFERSIZE 4096 static MtexPolyIdx pidx[MTEX_INDEXSIZE]; static int polypointer = 0; static W3D_VAVertex *mtex_pbuffer = NULL; GLboolean AllocMtex() { int i; if(mtex_pbuffer == NULL) { mtex_pbuffer = (W3D_VAVertex *) malloc( sizeof(W3D_VAVertex) * MTEX_VERTEXBUFFERSIZE); } if(!mtex_pbuffer) return GL_FALSE; return GL_TRUE; } void FreeMtex(void) { if(mtex_pbuffer) free(mtex_pbuffer); } #define CPACK(r,g,b,a) \ (ULONG)( (((ULONG)((a)*255.f))<<24) | (((ULONG)((r)*255.f))<<16) | (((ULONG)((g)*255.f))<<8) | ((ULONG)(b*255.f)) ) static void v_MtexToScreen_Flat(GLcontext context, int i, int bufpointer) { float x,y,z,w; float az; if (context->ZOffset_State == GL_TRUE) az = context->az + context->ZOffset; else az = context->az; w = 1.0 / context->VertexBuffer[i].bw; x = context->ax + context->VertexBuffer[i].bx * w * context->sx; y = context->ay - context->VertexBuffer[i].by * w * context->sy; z = az + context->VertexBuffer[i].bz * w * context->sz; mtex_pbuffer[bufpointer].x = x; mtex_pbuffer[bufpointer].y = y; mtex_pbuffer[bufpointer].z = z; mtex_pbuffer[bufpointer].w = w; mtex_pbuffer[bufpointer].s1 = context->VertexBuffer[i].v.u; mtex_pbuffer[bufpointer].t1 = context->VertexBuffer[i].v.v; mtex_pbuffer[bufpointer].s2 = context->VertexBuffer[i].tcoord.s; mtex_pbuffer[bufpointer].t2 = context->VertexBuffer[i].tcoord.t; } static void v_MtexToScreen_Smooth(GLcontext context, int i, int bufpointer) { float x,y,z,w; float az; if (context->ZOffset_State == GL_TRUE) az = context->az + context->ZOffset; else az = context->az; w = 1.0 / context->VertexBuffer[i].bw; x = context->ax + context->VertexBuffer[i].bx * w * context->sx; y = context->ay - context->VertexBuffer[i].by * w * context->sy; z = az + context->VertexBuffer[i].bz * w * context->sz; mtex_pbuffer[bufpointer].x = x; mtex_pbuffer[bufpointer].y = y; mtex_pbuffer[bufpointer].z = z; mtex_pbuffer[bufpointer].w = w; mtex_pbuffer[bufpointer].s1 = context->VertexBuffer[i].v.u ; mtex_pbuffer[bufpointer].t1 = context->VertexBuffer[i].v.v ; mtex_pbuffer[bufpointer].s2 = context->VertexBuffer[i].tcoord.s; mtex_pbuffer[bufpointer].t2 = context->VertexBuffer[i].tcoord.t; mtex_pbuffer[bufpointer].color = CPACK(context->VertexBuffer[i].v.color.r, context->VertexBuffer[i].v.color.g, context->VertexBuffer[i].v.color.b, context->VertexBuffer[i].v.color.a); } static void ProjectMtex_Flat(GLcontext context, int numverts, int bufstart) { int i; int bufpointer; float az; float x,y,z,w; if (context->ZOffset_State == GL_TRUE) az = context->az + context->ZOffset; else az = context->az; i = 0; bufpointer = bufstart; do { w = 1.0 / context->VertexBuffer[i].bw; x = context->ax + context->VertexBuffer[i].bx * w * context->sx; y = context->ay - context->VertexBuffer[i].by * w * context->sy; z = az + context->VertexBuffer[i].bz * w * context->sz; mtex_pbuffer[bufpointer].x = x; mtex_pbuffer[bufpointer].y = y; mtex_pbuffer[bufpointer].z = z; mtex_pbuffer[bufpointer].w = w; mtex_pbuffer[bufpointer].s1 = context->VertexBuffer[i].v.u; mtex_pbuffer[bufpointer].t1 = context->VertexBuffer[i].v.v; mtex_pbuffer[bufpointer].s2 = context->VertexBuffer[i].tcoord.s; mtex_pbuffer[bufpointer].t2 = context->VertexBuffer[i].tcoord.t; i++; bufpointer++; } while (i < numverts); } static void ProjectMtex_Smooth(GLcontext context, int numverts, int bufstart) { int i; int bufpointer; float az; float x,y,z,w; if (context->ZOffset_State == GL_TRUE) az = context->az + context->ZOffset; else az = context->az; i = 0; bufpointer = bufstart; do { w = 1.0 / context->VertexBuffer[i].bw; x = context->ax + context->VertexBuffer[i].bx * w * context->sx; y = context->ay - context->VertexBuffer[i].by * w * context->sy; z = az + context->VertexBuffer[i].bz * w * context->sz; mtex_pbuffer[bufpointer].x = x; mtex_pbuffer[bufpointer].y = y; mtex_pbuffer[bufpointer].z = z; mtex_pbuffer[bufpointer].w = w; mtex_pbuffer[bufpointer].s1 = context->VertexBuffer[i].v.u; mtex_pbuffer[bufpointer].t1 = context->VertexBuffer[i].v.v; mtex_pbuffer[bufpointer].s2 = context->VertexBuffer[i].tcoord.s; mtex_pbuffer[bufpointer].t2 = context->VertexBuffer[i].tcoord.t; mtex_pbuffer[bufpointer].color = CPACK(context->VertexBuffer[i].v.color.r, context->VertexBuffer[i].v.color.g, context->VertexBuffer[i].v.color.b, context->VertexBuffer[i].v.color.a); i++; bufpointer++; } while (i < numverts); } void d_DrawSmoothPoly(GLcontext context) { int i,j; ULONG and_code, or_code, local_or, guard_band; ULONG error; static MGLPolygon poly; static W3D_Vertex **verts = NULL; static W3D_TrianglesV fan; static ULONG complete[MGL_MAXVERTS]; int triangle; int nocull; int pnum, free; if(context->VertexBufferPointer < 3) return; if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK) return; v_Transform(context); and_code = 0xff; or_code = 0; for (i=0; i<context->VertexBufferPointer; i++) { MGLVertex *v = &(context->VertexBuffer[i]); float w = v->bw; ULONG outcode = 0; if (w < CLIP_EPS ) { outcode |= MGL_CLIP_NEGW; } if (-w > v->bx) { outcode |= MGL_CLIP_LEFT; } else if (v->bx > w) { outcode |= MGL_CLIP_RIGHT; } if (-w > v->by) { outcode |= MGL_CLIP_BOTTOM; } else if (v->by > w) { outcode |= MGL_CLIP_TOP; } if (-w > v->bz) { outcode |= MGL_CLIP_BACK; } else if (v->bz > w) { outcode |= MGL_CLIP_FRONT; } v->outcode = outcode; and_code &= outcode; or_code |= outcode; poly.verts[i] = i; } if (and_code) return; if (verts == NULL) { verts = (W3D_Vertex **)malloc(sizeof(W3D_Vertex *) * context->VertexBufferSize); if (!verts) return; } poly.numverts = context->VertexBufferPointer; #if defined(PRIORITIZE_BANDWIDTH) || defined(PRIORITIZE_FILRATE) //try to shrink primitive: if(context->VertexBuffer[0].outcode && poly.numverts > 3) { ULONG local_and; int size; int first; first = 0; i = poly.numverts - 2; local_and = context->VertexBuffer[0].outcode & context->VertexBuffer[i].outcode & context->VertexBuffer[i+1].outcode; if(local_and) { i--; while (i) { if((local_and & context->VertexBuffer[i].outcode) == 0) break; i--; } } size = i+2; if(size > 3) { i = 1; local_and = context->VertexBuffer[0].outcode & context->VertexBuffer[i].outcode & context->VertexBuffer[i+1].outcode; if(local_and) { i++; while (i < size-2) { if((local_and & context->VertexBuffer[i+1].outcode) == 0) break; i++; } } first = i-1; } if((size < poly.numverts) || first) { context->VertexBufferPointer = size; poly.numverts = size - first; or_code = context->VertexBuffer[0].outcode; i = 1; do { poly.verts[i] = first+i; or_code |= context->VertexBuffer[first+i].outcode; i++; } while (i < poly.numverts); } } #endif //guardband-test: if(or_code == 0 || (or_code & context->ClipFlags)) { guard_band = or_code; } else { guard_band = 0; i = 0; do { MGLVertex *v = &context->VertexBuffer[poly.verts[i]]; if(v->outcode) { float gcw = v->bw * 2.0; if (-gcw > v->bx) guard_band |= MGL_CLIP_LEFT; else if (v->bx > gcw) guard_band |= MGL_CLIP_RIGHT; if (-gcw > v->by) guard_band |= MGL_CLIP_BOTTOM; else if (v->by > gcw) guard_band |= MGL_CLIP_TOP; } i++; } while (i < poly.numverts && guard_band == 0); } if(guard_band == 0) { int vert; if( poly.numverts == 3 && context->CullFace_State == GL_TRUE) { if( hc_DecideFrontface(context, &context->VertexBuffer[0], &context->VertexBuffer[poly.verts[1]], &context->VertexBuffer[poly.verts[1] + 1]) == GL_FALSE) return; } PrepTexCoords(context, poly.verts[1], poly.numverts, GL_TRUE); verts[0] = &(context->VertexBuffer[0].v); v_ToScreen(context, 0); vert = poly.verts[1]; i = 1; do { verts[i] = &(context->VertexBuffer[vert].v); v_ToScreen(context, vert); i++; vert++; } while (i < poly.numverts); fan.tex = context->w3dTexBuffer[context->CurrentBinding]; fan.st_pattern = NULL; fan.v = verts; fan.vertexcount = poly.numverts; error = W3D_DrawTriFanV(context->w3dContext, &fan); return; } i = poly.verts[1]; triangle = 0; if(context->CullFace_State == GL_FALSE) { do { complete[triangle] = context->VertexBuffer[0].outcode | context->VertexBuffer[i].outcode | context->VertexBuffer[i+1].outcode; triangle++; i++; } while (i < context->VertexBufferPointer-1); } else { nocull = 0; do { local_or = context->VertexBuffer[0].outcode | context->VertexBuffer[i].outcode | context->VertexBuffer[i+1].outcode; complete[triangle] = local_or; if(local_or & MGL_CLIP_NEGW) { nocull = 1; } else if(nocull == 0) { if(hc_DecideFrontface(context, &context->VertexBuffer[0], &context->VertexBuffer[i], &context->VertexBuffer[i+1]) == GL_TRUE) { nocull = 1; } } i++; triangle++; } while (i < context->VertexBufferPointer - 1); //early out: if(nocull == 0) return; } PrepTexCoords(context, poly.verts[1], poly.numverts, GL_TRUE); i = poly.verts[1]; triangle = 0; free = context->VertexBufferPointer; pnum = 0; do { if (complete[triangle]) // case 1 { static MGLPolygon cpoly; cpoly.numverts = 3; cpoly.verts[0] = 0; cpoly.verts[1] = i; cpoly.verts[2] = i + 1; hc_ClipPoly(context, &cpoly, &clip[pnum], free, complete[triangle]); if(clip[pnum].numverts) { free = clip[pnum].nextfree; pnum++; } i++; triangle++; } else { // case 2 (the difficult part) int k=3; clip[pnum].verts[0] = 0; clip[pnum].verts[1] = i; clip[pnum].verts[2] = i+1; triangle ++; i ++; while (complete[triangle]==0 && i<context->VertexBufferPointer - 1) { clip[pnum].verts[k] = i+1; i++; k++; triangle++; } clip[pnum].numverts = k; pnum++; } } while (i<context->VertexBufferPointer-1); //project clipverts // mark unprojected verts within the vertexbuffer-range for(i=0; i<context->VertexBufferPointer; i++) { complete[i] = 0; } for(i=context->VertexBufferPointer; i<free; i++) { v_ToScreen(context, i); } fan.tex = context->w3dTexBuffer[context->CurrentBinding]; fan.st_pattern = NULL; fan.v = verts; j = 0; do { PolyBuffer *p = &clip[j]; for (i=0; i<p->numverts; i++) { int vert = p->verts[i]; if(vert < context->VertexBufferPointer && complete[vert] == 0) { complete[vert] = 1; v_ToScreen(context, vert); } verts[i] = &(context->VertexBuffer[vert].v); } fan.vertexcount = p->numverts; error = W3D_DrawTriFanV(context->w3dContext, &fan); } while (++j < pnum); } void d_DrawMtexPoly(GLcontext context) { int i,j; ULONG and_code, or_code, guard_band; static MGLPolygon poly; static int mtexverts; static int start; if(context->VertexBufferPointer < 3) return; if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK) return; v_Transform(context); and_code = 0xff; or_code = 0; for (i=0; i<context->VertexBufferPointer; i++) { MGLVertex *v = &(context->VertexBuffer[i]); float w = v->bw; ULONG outcode = 0; if (w < CLIP_EPS ) { outcode |= MGL_CLIP_NEGW; } if (-w > v->bx) { outcode |= MGL_CLIP_LEFT; } else if (v->bx > w) { outcode |= MGL_CLIP_RIGHT; } if (-w > v->by) { outcode |= MGL_CLIP_BOTTOM; } else if (v->by > w) { outcode |= MGL_CLIP_TOP; } if (-w > v->bz) { outcode |= MGL_CLIP_BACK; } else if (v->bz > w) { outcode |= MGL_CLIP_FRONT; } v->outcode = outcode; and_code &= outcode; or_code |= outcode; poly.verts[i] = i; } if (and_code) return; poly.numverts = context->VertexBufferPointer; #if defined(PRIORITIZE_BANDWIDTH) || defined(PRIORITIZE_FILRATE) //try to shrink primitive: if(context->VertexBuffer[0].outcode && poly.numverts > 3) { ULONG local_and; int size; int first; first = 0; i = poly.numverts - 2; local_and = context->VertexBuffer[0].outcode & context->VertexBuffer[i].outcode & context->VertexBuffer[i+1].outcode; if(local_and) { i--; while (i) { if((local_and & context->VertexBuffer[i].outcode) == 0) break; i--; } } size = i+2; if(size > 3) { i = 1; local_and = context->VertexBuffer[0].outcode & context->VertexBuffer[i].outcode & context->VertexBuffer[i+1].outcode; if(local_and) { i++; while (i < size-2) { if((local_and & context->VertexBuffer[i+1].outcode) == 0) break; i++; } } first = i-1; } if((size < poly.numverts) || first) { context->VertexBufferPointer = size; poly.numverts = size - first; or_code = context->VertexBuffer[0].outcode; i = 1; do { poly.verts[i] = first+i; or_code |= context->VertexBuffer[first+i].outcode; i++; } while (i < poly.numverts); } } #endif if( poly.numverts == 3 && context->CullFace_State == GL_TRUE && !(or_code & MGL_CLIP_NEGW) ) { if( hc_DecideFrontface(context, &context->VertexBuffer[0], &context->VertexBuffer[poly.verts[1]], &context->VertexBuffer[poly.verts[1] + 1]) == GL_FALSE) return; } //guardband-test if(or_code == 0 || (or_code & context->ClipFlags)) { guard_band = or_code; } else { i = 0; guard_band = 0; do { MGLVertex *v = &context->VertexBuffer[poly.verts[i]]; if(v->outcode) { float gcw = v->bw * 2.0; if (-gcw > v->bx) guard_band |= MGL_CLIP_LEFT; else if (v->bx > gcw) guard_band |= MGL_CLIP_RIGHT; if (-gcw > v->by) guard_band |= MGL_CLIP_BOTTOM; else if (v->by > gcw) guard_band |= MGL_CLIP_TOP; } i++; } while (i < poly.numverts && guard_band == 0); } if(polypointer == 0) mtexverts = 0; //reset start = mtexverts; if(or_code == 0) { if(context->ShadeModel == GL_SMOOTH) { ProjectMtex_Smooth(context, poly.numverts, mtexverts); } else { ProjectMtex_Flat(context, poly.numverts, mtexverts); } mtexverts += poly.numverts; } else { if(guard_band) { hc_ClipPolyFF(context, &poly, or_code); if(!poly.numverts) return; } if(context->ShadeModel == GL_SMOOTH) { for(i=0; i< poly.numverts; i++) { v_MtexToScreen_Smooth(context, poly.verts[i], mtexverts++); } } else { for(i=0; i< poly.numverts; i++) { v_MtexToScreen_Flat(context, poly.verts[i], mtexverts++); } } } pidx[polypointer].count = poly.numverts; pidx[polypointer].first = start; pidx[polypointer].tmu[0] = context->w3dTexBuffer[context->CurrentBinding]; pidx[polypointer].tmu[1] = context->w3dTexBuffer[context->VirtualBinding]; polypointer++; } void d_DrawNormalPoly(GLcontext context) { int i,j; ULONG error; ULONG and_code, or_code, guard_band; static W3D_Vertex **verts = NULL; static W3D_TrianglesV fan; static MGLPolygon poly; if(context->VertexBufferPointer < 3) return; if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK) return; v_Transform(context); and_code = 0xff; or_code = 0; for (i=0; i<context->VertexBufferPointer; i++) { MGLVertex *v = &(context->VertexBuffer[i]); float w = v->bw; ULONG outcode = 0; if (w < CLIP_EPS ) { outcode |= MGL_CLIP_NEGW; } if (-w > v->bx) { outcode |= MGL_CLIP_LEFT; } else if (v->bx > w) { outcode |= MGL_CLIP_RIGHT; } if (-w > v->by) { outcode |= MGL_CLIP_BOTTOM; } else if (v->by > w) { outcode |= MGL_CLIP_TOP; } if (-w > v->bz) { outcode |= MGL_CLIP_BACK; } else if (v->bz > w) { outcode |= MGL_CLIP_FRONT; } v->outcode = outcode; and_code &= outcode; or_code |= outcode; poly.verts[i] = i; } if (and_code) return; if (verts == NULL) { verts = (W3D_Vertex **)malloc(sizeof(W3D_Vertex *) * context->VertexBufferSize); if (!verts) return; } poly.numverts = context->VertexBufferPointer; #if defined(PRIORITIZE_BANDWIDTH) || defined(PRIORITIZE_FILRATE) //try to shrink primitive: if(context->VertexBuffer[0].outcode && poly.numverts > 3) { ULONG local_and; int size; int first; first = 0; i = poly.numverts - 2; local_and = context->VertexBuffer[0].outcode & context->VertexBuffer[i].outcode & context->VertexBuffer[i+1].outcode; if(local_and) { i--; while (i) { if((local_and & context->VertexBuffer[i].outcode) == 0) break; i--; } } size = i+2; if(size > 3) { i = 1; local_and = context->VertexBuffer[0].outcode & context->VertexBuffer[i].outcode & context->VertexBuffer[i+1].outcode; if(local_and) { i++; while (i < size-2) { if((local_and & context->VertexBuffer[i+1].outcode) == 0) break; i++; } } first = i-1; } if((size < poly.numverts) || first) { context->VertexBufferPointer = size; poly.numverts = size - first; or_code = context->VertexBuffer[0].outcode; i = 1; do { poly.verts[i] = first+i; or_code |= context->VertexBuffer[first+i].outcode; i++; } while (i < poly.numverts); } } #endif if( poly.numverts == 3 && context->CullFace_State == GL_TRUE && !(or_code & MGL_CLIP_NEGW) ) { if( hc_DecideFrontface(context, &context->VertexBuffer[0], &context->VertexBuffer[poly.verts[1]], &context->VertexBuffer[poly.verts[1] + 1]) == GL_FALSE) return; } PrepTexCoords(context, poly.verts[1], poly.numverts, GL_TRUE); //guardband-test if(or_code == 0 || (or_code & context->ClipFlags)) { guard_band = or_code; } else { i = 0; guard_band = 0; do { MGLVertex *v = &context->VertexBuffer[poly.verts[i]]; if(v->outcode) { float gcw = v->bw * 2.0; if (-gcw > v->bx) guard_band |= MGL_CLIP_LEFT; else if (v->bx > gcw) guard_band |= MGL_CLIP_RIGHT; if (-gcw > v->by) guard_band |= MGL_CLIP_BOTTOM; else if (v->by > gcw) guard_band |= MGL_CLIP_TOP; } i++; } while (i < poly.numverts && guard_band == 0); } if(guard_band == 0) { int vert; verts[0] = &(context->VertexBuffer[0].v); v_ToScreen(context, 0); vert = poly.verts[1]; i = 1; do { verts[i] = &(context->VertexBuffer[vert].v); v_ToScreen(context, vert); i++; vert++; } while (i < poly.numverts); } else { hc_ClipPolyFF(context, &poly, or_code); if(!poly.numverts) return; i=0; do { verts[i] = &(context->VertexBuffer[poly.verts[i]].v); v_ToScreen(context, poly.verts[i]); i++; } while(i < poly.numverts); } fan.tex = context->w3dTexBuffer[context->CurrentBinding]; fan.st_pattern = NULL; fan.vertexcount = poly.numverts; fan.v = verts; error = W3D_DrawTriFanV(context->w3dContext, &fan); } /* surgeon: added fast path when primitive or_code equals 0 surgeon: added buffering for clipping events surgeon: added a version (d_DrawTrianglesVA) that uses W3D_DrawElements/W3D_DrawArray for unclipped chains of triangles. (DrawFn) Pointer is set in GLEnd, based on the number of triangles in the pipeline. */ void d_DrawTriangles(GLcontext context) { #if !defined(DISABLE_TRANSFORMATION) int i,j; static W3D_TriangleV tri; ULONG or_code, and_code; ULONG error; if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK) return; v_Transform(context); for (i=0; i<context->VertexBufferPointer; i++) { MGLVertex *v = &(context->VertexBuffer[i]); float w = v->bw; ULONG outcode = 0; if (w < CLIP_EPS ) { outcode |= MGL_CLIP_NEGW; } if (-w > v->bx) { outcode |= MGL_CLIP_LEFT; } else if (v->bx > w) { outcode |= MGL_CLIP_RIGHT; } if (-w > v->by) { outcode |= MGL_CLIP_BOTTOM; } else if (v->by > w) { outcode |= MGL_CLIP_TOP; } if (-w > v->bz) { outcode |= MGL_CLIP_BACK; } else if (v->bz > w) { outcode |= MGL_CLIP_FRONT; } v->outcode = outcode; } tri.tex = context->w3dTexBuffer[context->CurrentBinding]; tri.st_pattern = NULL; for (i=0; i<context->VertexBufferPointer; i+=3) { or_code = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode | context->VertexBuffer[i+2].outcode; and_code = context->VertexBuffer[i+0].outcode & context->VertexBuffer[i+1].outcode & context->VertexBuffer[i+2].outcode; if (and_code) continue; if(context->CullFace_State == GL_TRUE && !(or_code & MGL_CLIP_NEGW)) { if (hc_DecideFrontface(context, &(context->VertexBuffer[i+0]), &(context->VertexBuffer[i+1]), &(context->VertexBuffer[i+2])) == GL_FALSE) continue; } PrepTexCoords(context, i, 3, GL_FALSE); if (or_code == 0) { v_ToScreen(context, i+0); v_ToScreen(context, i+1); v_ToScreen(context, i+2); tri.v1 = &(context->VertexBuffer[i+0].v); tri.v2 = &(context->VertexBuffer[i+1].v); tri.v3 = &(context->VertexBuffer[i+2].v); error = W3D_DrawTriangleV(context->w3dContext, &tri); } else { static MGLPolygon poly; poly.numverts = 3; poly.verts[0] = i+0; poly.verts[1] = i+1; poly.verts[2] = i+2; hc_ClipAndDrawPoly(context, &poly, or_code); } } #else int i; static W3D_TriangleV tri; ULONG error; PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE); for (i=0; i<context->VertexBufferPointer; i+=3) { v_ToScreen(context, i); v_ToScreen(context, i+1); v_ToScreen(context, i+2); tri.v1 = &(context->VertexBuffer[i+0].v); tri.v2 = &(context->VertexBuffer[i+1].v); tri.v3 = &(context->VertexBuffer[i+2].v); tri.tex = context->w3dTexBuffer[context->CurrentBinding]; tri.st_pattern = NULL; error = W3D_DrawTriangleV(context->w3dContext, &tri); } #endif } void d_DrawTrianglesVA(GLcontext context) { int i,j; ULONG or_code, and_code; ULONG error; ULONG vcount; //counter for vertices GLbitfield ClientState; GLboolean continous; GLfloat sign; UWORD *vaindex; v_Transform(context); for (i=0; i<context->VertexBufferPointer; i++) { MGLVertex *v = &(context->VertexBuffer[i]); float w = v->bw; ULONG outcode = 0; if (w < CLIP_EPS ) { outcode |= MGL_CLIP_NEGW; } if (-w > v->bx) { outcode |= MGL_CLIP_LEFT; } else if (v->bx > w) { outcode |= MGL_CLIP_RIGHT; } if (-w > v->by) { outcode |= MGL_CLIP_BOTTOM; } else if (v->by > w) { outcode |= MGL_CLIP_TOP; } if (-w > v->bz) { outcode |= MGL_CLIP_BACK; } else if (v->bz > w) { outcode |= MGL_CLIP_FRONT; } v->outcode = outcode; } vcount = 0; vaindex = &context->ElementIndex[0]; continous = GL_TRUE; //decide drawfunc sign = (GLfloat)-context->CurrentCullSign; for (i=0; i<context->VertexBufferPointer; i+=3) { or_code = context->VertexBuffer[i+0].outcode | context->VertexBuffer[i+1].outcode | context->VertexBuffer[i+2].outcode; and_code = context->VertexBuffer[i+0].outcode & context->VertexBuffer[i+1].outcode & context->VertexBuffer[i+2].outcode; if (and_code) { continous = GL_FALSE; continue; } if (or_code == 0) { v_ToScreenVA(context, i+0); v_ToScreenVA(context, i+1); v_ToScreenVA(context, i+2); if(context->CullFace_State == GL_TRUE) { GLfloat x1,x2,y1,y2; GLfloat area; #define x(a) (context->VertexBuffer[a].bx) #define y(a) (context->VertexBuffer[a].by) x1 = x(i+1) - x(i); y1 = y(i+1) - y(i); x2 = x(i+2) - x(i); y2 = y(i+2) - y(i); area = (y2*x1 - x2*y1) * sign; if (area < context->MinTriArea) { continous = GL_FALSE; continue; } #undef x #undef y } //build index for W3D_DrawElements vaindex[vcount+0] = i+0; vaindex[vcount+1] = i+1; vaindex[vcount+2] = i+2; vcount += 3; } else { static MGLPolygon poly; continous = GL_FALSE; if(context->CullFace_State == GL_TRUE && !(or_code & MGL_CLIP_NEGW)) { if (hc_DecideFrontface(context, &(context->VertexBuffer[i+0]), &(context->VertexBuffer[i+1]), &(context->VertexBuffer[i+2])) == GL_FALSE) continue; } PrepTexCoords(context, i, 3, GL_FALSE); poly.numverts = 3; poly.verts[0] = i+0; poly.verts[1] = i+1; poly.verts[2] = i+2; hc_ClipAndDrawPoly(context, &poly, or_code); } } ClientState = GLCS_VERTEX; if(context->Texture2D_State[0] == GL_FALSE) { Set_W3D_Texture(context->w3dContext, 0, NULL); } else { ClientState |= GLCS_TEXTURE; Set_W3D_Texture(context->w3dContext, 0, context->w3dTexBuffer[context->CurrentBinding]); Set_W3D_TexCoordPointer(context->w3dContext, (void*)&(context->VertexBuffer->v.u), sizeof(MGLVertex), 0, 4, -4, W3D_TEXCOORD_NORMALIZED); } Set_W3D_VertexPointer(context->w3dContext, (void*)&(context->VertexBuffer->bx), sizeof(MGLVertex), W3D_VERTEX_F_F_F, 0); if(context->ShadeModel == GL_SMOOTH) { ClientState |= GLCS_COLOR; Set_W3D_ColorPointer(context->w3dContext, (void*)&(context->VertexBuffer->v.color.r), sizeof(MGLVertex), W3D_COLOR_FLOAT, W3D_CMODE_RGBA, 0); } // draw with fastest method if(continous == GL_TRUE) { error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, 0, context->VertexBufferPointer); } else { error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, W3D_INDEX_UWORD, vcount, (void*)&vaindex[0]); } Reset_W3D_ArrayPointers(context, ClientState); } /* ** A MGL_FLATFAN / MGL_FLATSTRIP is a triangle fan or strip ** that is specified in device corrdinates and is drawn ** regardless of current matrix or viewport ** ** Very useful for bypassing the transformation pipeline ** */ void d_DrawFlat(GLcontext context) { ULONG error; int i; static W3D_Vertex *verts[MGL_MAXVERTS]; static W3D_TrianglesV tris; PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE); for (i=0; i<context->VertexBufferPointer; i++) { verts[i] = &context->VertexBuffer[i].v; context->VertexBuffer[i].v.x = (W3D_Float) context->VertexBuffer[i].bx; context->VertexBuffer[i].v.y = (W3D_Float) context->VertexBuffer[i].by; context->VertexBuffer[i].v.z = (W3D_Double) context->VertexBuffer[i].bz; context->VertexBuffer[i].v.w = (W3D_Float) context->VertexBuffer[i].bw; } tris.tex = context->w3dTexBuffer[context->CurrentBinding]; tris.st_pattern = NULL; tris.v = verts; tris.vertexcount = context->VertexBufferPointer; #ifndef NODRAW if(context->CurrentPrimitive == MGL_FLATSTRIP) { error = W3D_DrawTriStripV(context->w3dContext, &tris); } else //MGL_FLATFAN { error = W3D_DrawTriFanV(context->w3dContext, &tris); } #endif } void dh_DrawPoly(GLcontext context, MGLPolygon *poly) { int i; ULONG error; static W3D_Vertex *verts[8];//max clipverts for quad static W3D_TrianglesV tris; for (i=0; i<poly->numverts; i++) { v_ToScreen(context, poly->verts[i]); verts[i] = &(context->VertexBuffer[poly->verts[i]].v); } tris.tex = context->w3dTexBuffer[context->CurrentBinding]; tris.st_pattern = NULL; tris.vertexcount = poly->numverts; tris.v = verts; #ifndef NODRAW error = W3D_DrawTriFanV(context->w3dContext, &tris); #endif } /* ** See below for the interface to MiniGL/OpenGL */ static void d_DrawMtexPolyChains(GLcontext context, GLuint unit, GLuint size) { int i; ULONG error; if(unit == 0) { i = 0; do { Set_W3D_Texture(context->w3dContext, 0, pidx[i].tmu[0]); error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, pidx[i].first, pidx[i].count); i++; } while(i < size); } else { i = 0; do { Set_W3D_Texture(context->w3dContext, 0, pidx[i].tmu[1]); error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, pidx[i].first, pidx[i].count); i++; } while(i < size); } } /* ** MiniGL API: mglDrawMultitexBuffer(GLenum bs, GLenum bd, GLenum env) where bs = BlendSrc, bd = BlendDst, env = TexEnv This function should be called when all polys are in chain or a global state change make it required. It sets the supplied state-parameters, draws the buffer, and returns the context as it was before. ** */ void MGLDrawMultitexBuffer (GLcontext context, GLenum BSrc, GLenum BDst, GLenum TexEnv) { GLboolean blendfunc_changed; GLboolean depthmask_changed; GLbitfield ClientState; GLenum CurBlendSrc, CurBlendDst; if(polypointer == 0) return; #ifdef AUTOMATIC_LOCKING_ENABLE if (context->LockMode != MGL_LOCK_MANUAL) { if (context->LockMode == MGL_LOCK_AUTOMATIC) // Automatic: Lock per primitive { if (W3D_SUCCESS == W3D_LockHardware(context->w3dContext)) { context->w3dLocked = GL_TRUE; } else { printf("Error during LockHardware\n"); } } else // Smart: Lock timer based { if (context->w3dLocked == GL_FALSE) { if (W3D_SUCCESS != W3D_LockHardware(context->w3dContext)) { return; // give up } context->w3dLocked = GL_TRUE; TMA_Start(&(context->LockTime)); } } } #endif if (context->FogDirty && context->Fog_State) { fog_Set(context); context->FogDirty = GL_FALSE; } if(context->CurTexEnv != TexEnv) { W3D_Texture *tex = pidx[0].tmu[1]; switch(TexEnv) { case GL_MODULATE: W3D_SetTexEnv(context->w3dContext, tex, W3D_MODULATE, NULL); break; case GL_DECAL: W3D_SetTexEnv(context->w3dContext, tex, W3D_DECAL, NULL); break; default: case GL_REPLACE: W3D_SetTexEnv(context->w3dContext, tex, W3D_REPLACE, NULL); break; } } if(context->CurBlendSrc != BSrc || context->CurBlendDst != BDst) { CurBlendSrc = context->CurBlendSrc; CurBlendDst = context->CurBlendDst; GLBlendFunc(context, BSrc, BDst); blendfunc_changed = GL_TRUE; } else { blendfunc_changed = GL_FALSE; } //set vertexpointer to the multitexturebuffer Set_W3D_VertexPointer(context->w3dContext, (void*)&mtex_pbuffer[0].x, sizeof(W3D_VAVertex), W3D_VERTEX_F_F_F, 0); //set the texcoordpointer to tmu0 coords: Set_W3D_TexCoordPointer(context->w3dContext, (void*)&mtex_pbuffer[0].s1, sizeof(W3D_VAVertex), 0, 4, -4, W3D_TEXCOORD_NORMALIZED); if(context->ShadeModel == GL_FLAT && context->UpdateCurrentColor == GL_TRUE) { W3D_SetCurrentColor(context->w3dContext, &context->CurrentColor); context->UpdateCurrentColor = GL_FALSE; } else if(context->ShadeModel == GL_SMOOTH) { Set_W3D_ColorPointer(context->w3dContext, (void*)&mtex_pbuffer[0].color, sizeof(W3D_VAVertex), W3D_COLOR_UBYTE, W3D_CMODE_ARGB, 0); } //draw the buffered primitives for tmu[0] d_DrawMtexPolyChains(context, 0, polypointer); #if 0 //Disable Zbuffer updates for second pass if(context->DepthMask == GL_TRUE) { W3D_SetState(context->w3dContext, W3D_ZBUFFERUPDATE, W3D_DISABLE); depthmask_changed = GL_TRUE; } else { depthmask_changed = GL_FALSE; } #endif //switch the texcoordpointer to tmu1 coords: Set_W3D_TexCoordPointer(context->w3dContext, (void*)&mtex_pbuffer[0].s2, sizeof(W3D_VAVertex), 0, 4, -12, W3D_TEXCOORD_NORMALIZED); //draw the buffered primitives for tmu[1] with blending enabled: ENABLE_BLEND d_DrawMtexPolyChains(context, 1, polypointer); DISABLE_BLEND polypointer = 0; //reset the buffer //restore vertexpointers to their previous position ClientState = GLCS_VERTEX | GLCS_TEXTURE; if(context->ShadeModel == GL_SMOOTH) { ClientState |= GLCS_COLOR; } Reset_W3D_ArrayPointers(context, ClientState); #if 0 if(depthmask_changed == GL_TRUE) { W3D_SetState(context->w3dContext, W3D_ZBUFFERUPDATE, W3D_ENABLE); } #endif //reset states to entry-level if(blendfunc_changed == GL_TRUE) { GLBlendFunc(context, CurBlendSrc, CurBlendDst); } if(context->CurTexEnv != TexEnv) { W3D_Texture *tex = pidx[0].tmu[1]; switch(context->CurTexEnv) { case GL_MODULATE: W3D_SetTexEnv(context->w3dContext, tex, W3D_MODULATE, NULL); break; case GL_DECAL: W3D_SetTexEnv(context->w3dContext, tex, W3D_DECAL, NULL); break; default: case GL_REPLACE: W3D_SetTexEnv(context->w3dContext, tex, W3D_REPLACE, NULL); break; } } #ifdef AUTOMATIC_LOCKING_ENABLE if(context->LockMode != MGL_LOCK_MANUAL) { if(context->LockMode == MGL_LOCK_AUTOMATIC) { W3D_UnLockHardware(context->w3dContext); context->w3dLocked = GL_FALSE; } else if (context->LockMode == MGL_LOCK_SMART && TMA_Check(&(context->LockTime)) == GL_TRUE) { // Time to unlock W3D_UnLockHardware(context->w3dContext); context->w3dLocked = GL_FALSE; } } #endif } #ifdef __VBCC__ #undef v_ToScreen #undef v_ToScreenVA #endif